package net.apexcns.core.web.file;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;

import net.apexcns.core.config.ConfigEnv;
import net.apexcns.core.util.FileUtil;

import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.log4j.Logger;


@SuppressWarnings("serial")
public class FileItem extends DiskFileItem {
	private static Logger logger = Logger.getLogger(FileItem.class);
	private static ConfigEnv configEnv = ConfigEnv.getConfig(ConfigEnv.class);
	private File realFile;

	public FileItem(String fieldName, String contentType, boolean isFormField
			, String fileName, int sizeThreshold, File repository) {
		super(fieldName, contentType, isFormField, fileName, sizeThreshold, repository);
	}

	public void write(File file) {
		throw new UnsupportedOperationException("write(String) 함수를 사용하십시오.");
	}

	/** body: 확장자를 뺀 저장하고자 하는 파일명
	 *	파일 중복시 body[1].ext 형태로 증가
	 */
	public void write(String path, String body) throws Exception {
		write(path, body, false);
	}

	/** body: 확장자를 뺀 저장하고자 하는 파일명
	 *	body.ext로 생성되며 파일 중복시 덮어씀
	 */
	public void overwrite(String path, String body) throws Exception {
		write(path, body, true);
	}

	/** body.ext로 생성되며 파일 중복시 덮어씀 */
	public void overwrite(String path) throws Exception {
		write(path, getFilenameBody(), true);
	}

	/** body[1].ext로 생성되어 파일 중복시 증가 */
	public void write(String path) throws Exception {
		write(path, getFilenameBody(), false);
	}

	/** body: 확장자를 뺀 저장하고자 하는 파일명
	 *	overwrite=true면 body.ext로 생성, false면 파일 중복시 body[1].ext 형태로 증가
	 */
	public void write(String path, String body, boolean overwrite) throws Exception {
		path = FileUtil.normalizePath(path);
		File filepath = new File(configEnv.getFileUploadRootDir() + "/" + path);
		if(!filepath.exists()) filepath.mkdirs();
		String name = getName();
		if(name==null || "".equals(name)) return;

		String ext = getFilenameExt();
		String filename = body + ("".equals(ext) ? "" : ".") + ext;
		
		realFile = new File(configEnv.getFileUploadRootDir() + "/" + path + "/" + filename);
		realFile = new File(realFile.getParent(), filename);
		if(!overwrite) {
			for(int i=0; !createNewFile(realFile) && i<9999;
				realFile = new File(realFile.getParent(), filename)) {
				i++;
				filename = body + "[" + i + "]" + ("".equals(ext) ? "" : ".") + ext;
			}
		}
		super.write(realFile);

		logger.debug("path=" + getRealFilePath() + ", name=" + getRealFileName() + ", size=" + getSize());
	}

	/** DB에서 insert/update 실패시 파일 삭제 */
	public void deleteRealFile() {
		try {
			if (realFile != null && realFile.exists())
				realFile.delete();
		} catch(Exception e) {
			logger.warn(e.getMessage(), e);
		}
	}

	/** DB에서 delete시 파일 삭제 */
	public static int deleteFile(String path, String filename) {
		File file = new File(configEnv.getFileUploadRootDir() + "/" + path + "/" + filename);
		try {
			if (file != null && file.exists())
				file.delete();
		} catch(Exception e) {
			logger.warn(e.getMessage(), e);
			return -1;
		}
		return 1;
	}

	/** 업로드한 파일명 */
	public  String getFilename() {
		String name = getName();
		if(name==null || "".equals(name)) return "";
		return name.substring(name.lastIndexOf('\\')+1);
	}

	/** 업로드한 확장자를 뺀 파일명 */
	public  String getFilenameBody() {
		String filename = getFilename();
		if(filename==null || "".equals(filename)) return "";
		int dot = filename.lastIndexOf(".");

		return dot!=-1 ? filename.substring(0,dot) : filename;
	}

	/** 업로드한 확장자명 */
	public String getFilenameExt() {
		String filename = getFilename();
		if(filename==null || "".equals(filename)) return "";
		int dot = filename.lastIndexOf(".");

		return dot!=-1 ? filename.substring(dot+1, filename.length()) : "";
	}

	public static void deleteRealFile(Object vo) {
		try {
			Field[] fields = vo.getClass().getFields();
			for(int i=0; i<fields.length; i++) {
				Object f = fields[i].get(vo);
				try {
					if(fields[i].getType().isArray()) {
						Object[] fs = (Object[]) fields[i].get(vo);
						for(int j=0; j<fs.length; j++) {
							invokeDeleteRealFile(fs[j]);
						}
					} else {
						invokeDeleteRealFile(f);
					}
				} catch(Exception e) {
					//CmmUtil.debugStackTrace(e);
				}
			}
		} catch(Exception e) {
			logger.warn(e.getMessage(), e);
		}
	}

	private static void invokeDeleteRealFile(Object f) {
		try {
			if(f instanceof FileItem) {
				FileItem fileItem = (FileItem) f;
				fileItem.deleteRealFile();
				//f.getClass().getMethod("deleteRealFile", null).invoke(f, null);
			}
		} catch (Exception e) {
		}
	}
	
	public static void write(Object vo, String path) {
		try {
			Field[] fields = vo.getClass().getFields();
			for(int i=0; i<fields.length; i++) {
				Object f = fields[i].get(vo);
				try {
					if(fields[i].getType().isArray()) {
						Object[] fs = (Object[]) fields[i].get(vo);
						for(int j=0; j<fs.length; j++) {
							invokeWrite(fs[j], path);
						}
					} else {
						invokeWrite(f, path);
					}
				} catch(Exception e) {
					logger.warn(e.getMessage(), e);
				}
			}
		} catch(Exception e) {
			logger.warn(e.getMessage(), e);
		}
	}

	private static void invokeWrite(Object f, String path) {
		try {
			if(f instanceof FileItem) {
				FileItem fileItem = (FileItem) f;
				fileItem.write(path);
				//f.getClass().getMethod("write", new Class[]{String.class}).invoke(f, new Object[]{path});
			}
		} catch (Exception e) {
		}
	}
	
	public String getRealFileName() {
		String name = "";
		try {
			name = realFile.getName();
		} catch (Exception e) {
		}
		return name;
	}
	
	public String getRealFilePath() {
		String name = "";
		try {
			name = realFile.getCanonicalPath();
		} catch (Exception e) {
		}
		return name;
	}


	public boolean createNewFile(File file) {
		try {
			return file.createNewFile();
		} catch (IOException ignored) {
			return false;
		}
	}
}
